//David Wasser
//February 18, 2009
//Software Design, Period 6
//Ultimate Frisbee

/* OffStack is the Strategy that controls the routines
 * in an offensive stack (OffStack) strategy in which the players
 * line up in the middle of the field and cut towards or away
 * from the thrower with the disc to try to get open.
 */
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
public class OffStack extends OffStrategy{
	private short[] order;
	private Object[] catcher;
	private Point3d stackStart;
	private boolean test = false; //true if going right
	ArrayList<Player> stackOrd = new ArrayList<Player>();
	Iterator<Player> it;
	ArrayList<Player> temp = new ArrayList<Player>();
	private Player temp2;
	private Set<Player> test2;

	/** Creates a new OffStack for the given Team
	 ** on the given Field with Players lined up on the lines.
	 **/
	public OffStack(Team team, Field field){
		super(team, field);
		double temp1 = Field.bounds.y/14;
		Point3d temp2;
		if(team.endZone == Team.RIGHT)
			temp2 = new Point3d(Field.GOAL, Field.bounds.y/4, 0);
		else
			temp2 = new Point3d(Field.bounds.x-Field.GOAL, Field.bounds.y/4, 0);
		for(int i=0; i<7; i++){
			routes.put(i, new OffStackRoutine(team.players.get(i), (Point3d) temp2.clone(), this));
			team.players.get(i).position = (Point3d) temp2.clone();
			team.players.get(i).velocity = new Vector3d((team.endZone == Team.RIGHT?1:-1),0,0);
			if(field != null)
				if(team.players.get(i) == field.playerWithDisc)
					team.players.get(i).setMovementRoutine(new ThrowingRoutine(team.players.get(i), field.disc, null));
			temp2.y += temp1;
		}//End for
		if(field == null)
			starting = true;
	}//End OffStack()
	
	/** Creates an OffStack with the given Players, Team, and Field
	 **/
	public OffStack(Set<Player> players, Team team, Field field){
		super(team, field);
		it = players.iterator();
		Player temp1;
		for(int i=0; it.hasNext(); i++){
			temp1 = it.next();
			routes.put(i, new OffStackRoutine(temp1, temp1.position, this));
		}//End while
	}//End OffStack
	
	/** Tells all of the OffStackRoutines to line up the
	 ** Players in a line in the field.
	 **/
	protected void stack(){
		stackOrd = field.playersByX(team.side);
		if(team.endZone == team.RIGHT){
			it = stackOrd.iterator();
			while(it.hasNext())
				temp.add(it.next());
			stackOrd = temp;
			test = true;
		}//End if
		it = stackOrd.iterator();
		if(test){
			stackStart = new Point3d((field.bounds.x + 3*field.disc.position.x)/4, field.bounds.y/2, 0);
			for(int i=1; it.hasNext(); i++){
				temp2 = it.next();
				if(!(temp2.routine instanceof UserMovementRoutine))
					((OffStackRoutine)temp2.routine).setStackPos(new Point3d(2*i+stackStart.x, stackStart.y, 0));
			}//End for
		}else{
			stackStart = new Point3d(3*field.disc.position.x/4, field.bounds.y/2, 0);
			for(int i=1; it.hasNext(); i++){
				temp2 = it.next();
				if(!(temp2.routine instanceof UserMovementRoutine))
					((OffStackRoutine)temp2.routine).setStackPos(new Point3d(stackStart.x-2*i, stackStart.y, 0));
			}//End for
		}//End else
	}//End stack()
	
	/** This is called whenever the disc is either caught
	 ** or thrown with the catcher/thrower as the input.
	 ** It moves a Player to catch the disc.
	 **/
	public void discChange(Player player){
		if(starting)
			starting = false;
		if(field.disc.isHeld()){
			stack();
			if(team.isPlayerOnTeam(player))
				player.setMovementRoutine(new ThrowingRoutine(player, field.disc, player.routine));
		}else{
			test2 = new HashSet<Player>(team.getPlayers());
			test2.remove(player);
			catcher = getClosestToDisc(field.disc, team.getPlayers(), field.dt);
			if(!(((Player)catcher[0]).routine instanceof UserMovementRoutine))
				((OffStackRoutine)((Player)catcher[0]).routine).setCatching((Point3d)catcher[1]);
		}//End else
	}//End discChange()
}//End OffStack